// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: jaewon

#include "coin1/base/math/moving_window.h"

#include <gtest/gtest.h>
#include <xtensor/xarray.hpp>

namespace math {

TEST(MovingWindowTest, Basic) {
  SimpleMovingWindow<int> window;

  window.Push(0);
  EXPECT_EQ(window.size(), 0);
  EXPECT_TRUE(window.empty());
  EXPECT_EQ(window.num_popped(), 1);
}

TEST(MovingWindowTest, Basic2) {
  SimpleMovingWindow<int> window;
  window.ResizeWindow(2);
  EXPECT_EQ(window.window_size(), 2);

  window.Push(1);
  EXPECT_EQ(window.size(), 1);
  EXPECT_FALSE(window.empty());
  EXPECT_EQ(window.num_popped(), 0);

  window.Push(2);
  EXPECT_EQ(window.size(), 2);
  EXPECT_EQ(window.num_popped(), 0);

  window.Push(3);
  EXPECT_EQ(window.size(), 2);
  EXPECT_EQ(window.num_popped(), 1);

  window.Push(4);
  window.Push(5);
  window.Push(6);
  window.Push(7);
  EXPECT_EQ(window.size(), 2);
  EXPECT_EQ(window.num_popped(), 5);

  EXPECT_EQ(window.front(), 6);
  EXPECT_EQ(window.back(), 7);
}

TEST(MovingWindowTest, LastValueWrapperTest) {
  SimpleMovingWindow<int, true> window;
  window.ResizeWindow(2);
  EXPECT_EQ(window.window_size(), 2);
  EXPECT_FALSE(window.handler().last_pushed.has_value());
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push(1);
  EXPECT_EQ(window.handler().last_pushed.value(), 1);
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push(2);
  EXPECT_EQ(window.handler().last_pushed.value(), 2);
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push(3);
  EXPECT_EQ(window.handler().last_pushed.value(), 3);
  EXPECT_EQ(window.handler().last_popped.value(), 1);

  window.Push(4);
  window.Push(5);
  window.Push(6);
  window.Push(7);
  EXPECT_EQ(window.handler().last_pushed.value(), 7);
  EXPECT_EQ(window.handler().last_popped.value(), 5);
}

TEST(MovingWindowTest, Xarray) {
  SimpleMovingWindow<xt::xarray<int>, true> window;
  window.ResizeWindow(2);
  EXPECT_EQ(window.window_size(), 2);
  EXPECT_FALSE(window.handler().last_pushed.has_value());
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push({{1, 2}, {3, 4}});
  EXPECT_EQ(window.handler().last_pushed.value(), xt::xarray<int>({{1, 2}, {3, 4}}));
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push({2});
  EXPECT_EQ(window.handler().last_pushed.value(), xt::xarray<int>({2}));
  EXPECT_FALSE(window.handler().last_popped.has_value());

  window.Push({3});
  EXPECT_EQ(window.handler().last_pushed.value(), xt::xarray<int>({3}));
  EXPECT_EQ(window.handler().last_popped.value(), xt::xarray<int>({{1, 2}, {3, 4}}));

  window.Push({4});
  window.Push({{1, 0}, {0, 1}});
  window.Push({6});
  window.Push({7});
  EXPECT_EQ(window.handler().last_pushed.value(), xt::xarray<int>({7}));
  EXPECT_EQ(window.handler().last_popped.value(), xt::xarray<int>({{1, 0}, {0, 1}}));
}

}  // namespace math
